/**
 * @file      adc_driver.c
 * @version   V1.0.0    
 * @date      2013-10-04
 * @brief     adc driver for Tananis on PA7.	
 * @author    - Adela 
 *            - Robert Zhang <armner@gmail.com>
 *            - 
 */

#include "stm32f2xx.h"
#include "interrupt.h"
#include "FreeRTOS.h"
#include "semphr.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"

#include "adc_driver.h"
static const char ana_direction[16] = {0,0,0,1,  0,0,0,0,  0};
static short adc_buffer[16];

#define SAMPTIME 2
#define NUMBER_ANALOG 9
#define STICK_LV    3
#define STICK_LH    2
#define STICK_RV    0
#define STICK_RH    1
#define POT_L       6
#define POT_R     8
#define SLIDE_L    14
#define SLIDE_R    15
#define BATTERY    10


int adc_open(Driver *driver)
{
    GPIO_InitTypeDef GPIO_InitStructure;
	  
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	  
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 |GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_4 |GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOC, &GPIO_InitStructure);


    ADC1->CR1 = ADC_CR1_SCAN ;
    ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_DMA | ADC_CR2_DDS ;
    ADC1->SQR1 = (NUMBER_ANALOG-1) << 20 ;             // NUMBER_ANALOG Channels
    ADC1->SQR2 = SLIDE_L + (SLIDE_R<<5) + (BATTERY<<10) ;
    ADC1->SQR3 = STICK_LH + (STICK_LV<<5) + (STICK_RV<<10) + (STICK_RH<<15) + (POT_L<<20) + (POT_R<<25) ;
    ADC1->SMPR1 = SAMPTIME + (SAMPTIME<<3) + (SAMPTIME<<6) + (SAMPTIME<<9) + (SAMPTIME<<12)
                                                          + (SAMPTIME<<15) + (SAMPTIME<<18) + (SAMPTIME<<21) + (SAMPTIME<<24) ;
    ADC1->SMPR2 = SAMPTIME + (SAMPTIME<<3) + (SAMPTIME<<6) + (SAMPTIME<<9) + (SAMPTIME<<12)
                                                          + (SAMPTIME<<15) + (SAMPTIME<<18) + (SAMPTIME<<21) + (SAMPTIME<<24) + (SAMPTIME<<27) ;

    ADC->CCR = 0 ; //ADC_CCR_ADCPRE_0 ;             // Clock div 2

    DMA2_Stream0->CR = DMA_SxCR_PL | DMA_SxCR_MSIZE_0 | DMA_SxCR_PSIZE_0 | DMA_SxCR_MINC ;
    DMA2_Stream0->PAR = (uint32_t)(&ADC1->DR);
    DMA2_Stream0->M0AR = (uint32_t)(adc_buffer);
    DMA2_Stream0->FCR = DMA_SxFCR_DMDIS | DMA_SxFCR_FTH_0 ;

    return 0;
}

int adc_write(Driver* driver, void *buffer, int len, OFFSET offset)
{
    return 0;
}


int adc_read(Driver* driver, void *buffer, int len, OFFSET offset)
{
    uint32_t i ;

    DMA2_Stream0->CR &= ~DMA_SxCR_EN ;              // Disable DMA
    ADC1->SR &= ~(uint32_t) ( ADC_SR_EOC | ADC_SR_STRT | ADC_SR_OVR ) ;
    DMA2->LIFCR = DMA_LIFCR_CTCIF0 | DMA_LIFCR_CHTIF0 |DMA_LIFCR_CTEIF0 | DMA_LIFCR_CDMEIF0 | DMA_LIFCR_CFEIF0 ; // Write ones to clear bits
    DMA2_Stream0->M0AR = (uint32_t)(adc_buffer);
    DMA2_Stream0->NDTR = NUMBER_ANALOG ;
    DMA2_Stream0->CR |= DMA_SxCR_EN ;               // Enable DMA
    ADC1->CR2 |= (uint32_t)ADC_CR2_SWSTART ;
    for (i=0; i<10000; i++) {
        if (DMA2->LISR & DMA_LISR_TCIF0)
        {
            break ;
        }
    }
    DMA2_Stream0->CR &= ~DMA_SxCR_EN ;              // Disable DMA

    // adc direction correct
    for (i=0; i<NUMBER_ANALOG; i++)
    {
        if (ana_direction[i])
        {
            adc_buffer[i] = 4095-adc_buffer[i];
        }
    }


    memcpy(buffer, adc_buffer, len);

    return len;

}

int adc_ioControl(Driver *driver, int cmd, int data)
{
    return 0;
}


int adc_close(Driver *driver)
{
    return 0;
}



Driver adc_driver=
{
    &adc_open,
    &adc_write,
    &adc_read,
    &adc_ioControl,
    &adc_close
};




